﻿/******************************************************
* author :  cwj
* email  :  chenwenji_360@live.com 
* history:  created by cwj 2015/7/16 16:18:23 
* clrversion :4.0.30319.18444
******************************************************/

using Machine.DataAccess.Common;
using Machine.DataAccess.Linq.Relation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Machine.DataAccess.Linq
{
    class DbVisitor : ExpressionVisitor
    {
        public override Expression Visit(Expression exp)
        {
            if (exp == null)
                return exp;
            switch ((ProjectionType)exp.NodeType)
            {
                case ProjectionType.Project:
                    return this.VisitProject(exp as ProjectionExpression);
                case ProjectionType.Select:
                    return this.VisitSelect(exp as SelectExpression);
                case ProjectionType.Table:
                    return this.VisitTable(exp as TableExpression);
                case ProjectionType.Colum:
                    return this.VisitColum(exp as ColumExpression);
                case ProjectionType.Join:
                    return this.VisitJoin(exp as JoinExpression);
                case ProjectionType.Like:
                    return this.VisitLike(exp as LikeExpression);
                case ProjectionType.Update:
                    return this.VisitUpdate(exp as UpdateExpression);
                //case ProjectionType.OrderBy:
                //    return this.VisitOrderBy(exp as OrderByExpression);
                default:
                    return base.Visit(exp);
            }
        }

        //protected virtual Expression VisitOrderBy(OrderByExpression order)
        //{
        //    var select = this.Visit(order.Select);
        //    var orderMember = this.Visit(order.Order);
        //    if (select != order.Select || order.Order != orderMember)
        //    {
        //        return new OrderByExpression(order.Type, select, orderMember);
        //    }
        //    return order;
        //}

        protected virtual Expression VisitLike(LikeExpression like)
        {
            this.Visit(like.Source);
            return like;
        }

        protected virtual Expression VisitProject(ProjectionExpression projection)
        {
            var select = this.Visit(projection.Selection) as SelectExpression;
            var project = this.Visit(projection.Projection);
            if (select != projection.Selection || project != projection.Projection)
            {
                return new ProjectionExpression(select, project);
            }
            return project;
        }

        protected virtual Expression VisitSelect(SelectExpression select)
        {
            var from = this.VisitSource(select.From);
            var where = this.Visit(select.Where);
            foreach (var item in select.OrderBy)
            {
                this.Visit(item.ColumExpression);
            }
            if (from != select.From || where != select.Where)
            {
                return new SelectExpression(select.Type, select.TableIndex, select.Colums, from, where, select.OrderBy);
            }
            return select;
        }

        protected virtual Expression VisitTable(TableExpression table)
        {
            return table;
        }

        protected virtual Expression VisitColum(ColumExpression colum)
        {
            return colum;
        }

        protected virtual Expression VisitSource(Expression source)
        {
            return this.Visit(source);
        }

        protected virtual Expression VisitJoin(JoinExpression join)
        {
            var left = this.Visit(join.Left);
            var right = this.Visit(join.Right);
            var on = this.Visit(join.On);
            if (join.Left != left || join.Right != right || join.On != on)
            {
                return new JoinExpression(join.Type, left, right, on);
            }
            return join;
        }

        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            throw new NotImplementedException("暂时不支持表达式内运行函数");
            //return base.VisitMethodCall(node);
        }

        protected virtual Expression VisitUpdate(UpdateExpression update)
        {
            this.Visit(update.Set);
            return update.Set;
        }
    }
}
